package utils

import (
	"context"
	"errors"
	"os/exec"
	"runtime"
	"time"
)

var (
	Shell = GetShell()
)

// RunCmd 执行bash命令，返回结果
// 有一秒钟的超时时间
func RunCmd(cmd string) ([]byte, int32, error) {
	ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
	defer cancel()
	switch runtime.GOOS {
	case "windows":
		if Shell != "cmd" {
			return nil, -1, errors.New("need cmd to run command")
		}
		command := exec.CommandContext(ctx, "cmd", "/C", cmd)
		output, err := command.CombinedOutput()
		code := command.ProcessState.ExitCode()
		return output, int32(code), err
	case "darwin":
		if Shell == "" {
			return nil, -1, errors.New("need shell to run command: zsh/bash/sh")
		}
		command := exec.CommandContext(ctx, Shell, "-c", cmd)
		output, err := command.CombinedOutput()
		code := command.ProcessState.ExitCode()
		return output, int32(code), err
	case "linux":
		if Shell == "" {
			return nil, -1, errors.New("need shell to run command: zsh/bash/sh")
		}
		command := exec.CommandContext(ctx, Shell, "-c", cmd)
		output, err := command.CombinedOutput()
		code := command.ProcessState.ExitCode()
		return output, int32(code), err
	default:
		return nil, -1, errors.New("unsupported os")
	}
}

// GetShell 获取系统可以使用的shell类型，如果存在多个shell，优先级为zsh > bash > sh
// 对于Windows，返回cmd
func GetShell() string {
	shells := []string{"zsh", "bash", "sh"}
	// f返回true表示有该shell
	f := func(s string) bool {
		cmd := exec.Command(s, "-c", "type "+s)
		_, err := cmd.CombinedOutput()
		return err == nil
	}
	switch runtime.GOOS {
	case "windows":
		cmd := exec.Command("where", "cmd")
		err := cmd.Run()
		if err != nil {
			return ""
		}
		return "cmd"
	case "linux":
		for _, s := range shells {
			if f(s) {
				return s
			}
		}
		return ""
	case "darwin": // macos
		for _, s := range shells {
			if f(s) {
				return s
			}
		}
		return ""
	default:
		return ""
	}
}

// CmdProbe 探测命令是否存在
func CmdProbe(cmd string) bool {
	switch runtime.GOOS {
	case "windows":
		command := exec.Command("where", cmd)
		err := command.Run()
		if err != nil {
			return false
		}
		return true
	case "linux":
		command := exec.Command(Shell, "-c", "type "+cmd)
		err := command.Run()
		if err != nil {
			return false
		}
		return true
	case "darwin":
		command := exec.Command(Shell, "-c", "type "+cmd)
		err := command.Run()
		if err != nil {
			return false
		}
		return true
	default:
		return false
	}
}
